﻿//Copyright md bravo - feel free to modify this code in any way - just leave this notice ;)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using ShareCDN.Engine.Data;

namespace ShareCDN.Engine.LocalStorage
{
	public class LocalStorageManager : StorageManager
	{
		const string StorageFolderVirtualPath = "~/App_Data/Data/";
		const string ExpirationFolderVirtualPath = "~/App_Data/Data/exp/";

		public LocalStorageManager()
		{
			var storageFolder = System.Web.Hosting.HostingEnvironment.MapPath(StorageFolderVirtualPath);
			if (!System.IO.Directory.Exists(storageFolder))
			{
				System.IO.Directory.CreateDirectory(storageFolder);
			}

			var expFolder = System.Web.Hosting.HostingEnvironment.MapPath(ExpirationFolderVirtualPath);
			if (!System.IO.Directory.Exists(expFolder))
			{
				System.IO.Directory.CreateDirectory(expFolder);
			}
		}


		public override Data.DownloadHandle GetHandle(string hashKey)
		{
			byte[] hashBytes = GetBytes(hashKey);
			var guidPart = hashBytes.Take(16).ToArray();
			var keyPart = hashBytes.Skip(16).ToArray();
			var guid = new Guid(guidPart);
			var rijndael = System.Security.Cryptography.Rijndael.Create();
			var decryptor = rijndael.CreateDecryptor(keyPart, keyPart.Skip(16).ToArray());
			var handle = new DownloadHandle();
			var fileName = guid.ToString();
			var completeFileName = System.Web.Hosting.HostingEnvironment.MapPath(StorageFolderVirtualPath + fileName);
			var innerStream = System.IO.File.OpenRead(completeFileName);
			Stream cryptoStream = new CryptoStream(innerStream, decryptor, CryptoStreamMode.Read);
			handle.Stream = cryptoStream;
			handle.DisposableObjects.Add(cryptoStream);
			handle.DisposableObjects.Add(innerStream);
			return handle;
		}

		public override Data.UploadedResult Upload(Data.UploadHandle uploadHandle)
		{


			byte[] encryptBytes = new byte[32];
			using (var generator = System.Security.Cryptography.RandomNumberGenerator.Create())
			{

				generator.GetNonZeroBytes(encryptBytes);

			}
			var fileNameGuid = Guid.NewGuid();
			var byteHash = new List<byte>();
			byteHash.AddRange(fileNameGuid.ToByteArray());
			byteHash.AddRange(encryptBytes);

			var base64Hash = GetEncodedBytes(byteHash.ToArray());
			var fileName = fileNameGuid.ToString();
			var completeFileName = System.Web.Hosting.HostingEnvironment.MapPath(StorageFolderVirtualPath + fileName);
			var dataFileName = completeFileName + "_nfo";
			var expirationDataFileName = System.Web.Hosting.HostingEnvironment.MapPath(ExpirationFolderVirtualPath + Guid.NewGuid().ToString());


			var rijndael = System.Security.Cryptography.Rijndael.Create();
			var encryptor = rijndael.CreateEncryptor(encryptBytes, encryptBytes.Skip(16).ToArray());
			using (var innerStream = System.IO.File.Open(completeFileName, FileMode.Create))
			{
				using (Stream cryptoStream = new CryptoStream(innerStream, encryptor, CryptoStreamMode.Write))
				{
					uploadHandle.Stream.CopyTo(cryptoStream);
				}
			}
			var result = new UploadedResult();
			result.SecretKey = base64Hash;

			return result;

		}


		private static string GetEncodedBytes(byte[] bytes)
		{
			var str = Convert.ToBase64String(bytes.ToArray());
			str = str.Replace("+", "-").Replace("/", "_").Replace("=", ".");
			return str;
		}

		private static byte[] GetBytes(string inputBase64)
		{
			var str = inputBase64.Replace("-", "+").Replace("_", "/").Replace(".", "=");
			return Convert.FromBase64String(str);
		}
	}
}
